<template>
  <!-- @click.stop="onBlankClick($event)" -->
  <div class="columns-container" @scroll="containerScroll">
    <data-column
      v-for="(column, i) in tableColumns"
      ref="dataColumn"
      :key="`${column.name}`"
      :order-number="formulaColIndex < 0 ? i : i < formulaColIndex ? i : i - 1"
      class="column-card"
      :tools="isPreviewMode ? null : []"
      :column="column"
      :table-name="tableName"
      :visible="i >= visibleRange[0] && i <= visibleRange[1]"
      :cache="columnQueryStatCache"
      :parent-table-name="parentTableName"
      :is-edit="isEditHistory"
      :task-id="selectNodeTableInfo.nodeId"
      :edit-data="currentHistory"
      :column-filters="columnFilters"
      :column-list="tableColumns"
      :column-index="i"
      :selected-columns="selectedColumns"
      :contextmenu-enable="false"
      :is-visitor="isVisitor"
      :show-index="showColumnIndex"
      :current-col="formulaColName"
      :project-id="projectId"
      @column-click="onDataColumnClick({}, column, i, true)"
      @click="onDataColumnClick($event, column, i)"
      @config-success="onColumnConfigSuccess"
      @config-cancel="onColumnConfigCancel"
      @bar-click="onColumnBarFilter"
      @contextmenu="onContextmenu"
      @semantic-change="(data) => onSemanticChange(data)"
      @openVRPanel="onOpenVRPanel"
      @closeRecomPart="onCloseRecomPart"
    />
    <div
      v-show="
        (!tableColumns || tableColumns.length === 0) && !isTableDetailLoading
      "
      class="empty-info"
    >
      <div v-if="selectNode && selectNode.type !== 4">
        <img alt="" src="@/assets/view/dataview-empty.svg" />
        <p v-if="selectNode && selectNode.data.isSample === 'SUCCESS'">
          全量执行后发现异常数据，无法显示结果
        </p>
        <p v-else>暂未发现有效数据</p>
      </div>
      <div v-else>
        <img alt="" src="@/assets/view/empty2.png" />
        <p>暂无数据 请先编辑算子</p>
        <!--        <span-->
        <!--          class="edit-opeartor-btn"-->
        <!--          :class="{ disable: isVisitor }"-->
        <!--          @click="openEditOperator"-->
        <!--        >-->
        <!--          <span>编辑算子</span>-->
        <!--        </span>-->
      </div>
    </div>
    <div
      v-show="contextmenuVisible"
      ref="contextmenuDropdown"
      class="contextmenu-box"
      :style="{
        left: `${contextmenuStyle.left}px`,
        top: `${contextmenuStyle.top}px`,
      }"
    >
      <ul class="ant-dropdown-menu">
        <li class="ant-dropdown-menu-item" @click="onContextmenuDelete">
          删除
        </li>
        <li class="ant-dropdown-menu-item" @click="onContextmenuRetain">
          仅保留
        </li>
      </ul>
    </div>
  </div>
</template>

<script lang="ts">
import { Vue, Component, Watch, Prop } from 'vue-property-decorator'
import DataColumn from '@/components/studio/data/node-edit-panel/DataColumn.vue'
import DataStore, { IColumn } from '@/store/modules/dataview'
import { debounce, isEqual, uniq } from 'lodash'
import {
  CleanFromVisAction,
  StatisticsAction,
} from '@/util/data-selection-actions'
import SelectionType from '@/util/selection-type'
import { IChangeSemanticData } from '@/components/studio/data/node-edit-panel/interface'

@Component({
  components: {
    DataColumn,
  },
})
export default class DataColumns extends Vue {
  @Prop({ default: false }) public isVisitor!: boolean // 是否访客模式

  private lastClickedColumnIndex: number | null = null
  private oldSelectedColumns: IColumn[] = []
  private contextmenuVisible: boolean = false // 右键菜单是否展示
  private contextmenuStyle: { top: number; left: number } = { top: 0, left: 0 } // 右键菜单样式
  private columnWidth = 180
  private pageSize = 6 // 可视区域可加载个数
  private visibleRange = [0, 0] // 数据列可视范围，[start index，end index]
  private columnQueryStatCache = {}

  private get showColumnIndex() {
    return DataStore.showColumnIndex
  }

  private get formulaColName() {
    return DataStore.formulaColName
  }

  private get projectId() {
    return DataStore.projectId
  }

  private get tableColumns(): IColumn[] {
    // 全部表列信息
    return DataStore.tableColumns
  }

  private get formulaColIndex() {
    //  NOT FOUND THEN -1
    const index = this.tableColumns.findIndex((x: any) => {
      return x.name === this.formulaColName
    })
    return index
  }

  private get selectedColumns(): IColumn[] {
    return DataStore.selectedColumns
  }

  private get selectNode() {
    return DataStore.selectNode
  }

  private get currentHistory() {
    return DataStore.currentHistory
  }

  private get isTableDetailLoading() {
    return DataStore.isTableDetailLoading
  }

  private get tableName(): string {
    // 查询数据的表名取决于当前历史记录的表名，没有的话取selectnode的表名
    if (DataStore.autojoinTableName) {
      // autojoin 预览表数据
      return DataStore.autojoinTableName
    }
    return this.selectNodeTableInfo?.tableName
  }

  public get selectNodeTableInfo() {
    // 节点id和表名组成的唯一信息
    return DataStore.selectNodeTableInfo || { nodeId: '', tableName: '' }
  }

  private get parentTableName(): string {
    if (this.isEditHistory) {
      const currentIndex = this.historyList.findIndex(
        (item) => item.data.id === this.currentHistory?.data.id
      )
      return this.historyList[
        currentIndex === 0 ? currentIndex : currentIndex - 1
      ].data.table // 编辑状态下是基于上一条记录的表名来进行筛选
    }
    return ''
  }

  private get isMac() {
    const { userAgent } = window.navigator
    return userAgent.includes('Mac OS X')
  }

  private get isEditHistory() {
    return DataStore.isEditHistory
  }

  private get historyList() {
    return DataStore.historyList
  }

  private get columnFilters() {
    return DataStore.columnFilters
  }

  // 合并快捷键触发
  private get mergeColumnHotKey() {
    return DataStore.mergeColumnHotKey
  }

  //  根据例子创建新列触发 from table
  private get createNewColumnFromTable() {
    return DataStore.ifOpenCreateNewColumn
  }

  //  获取 需要创建新列的列名 from table
  private get newColumnName() {
    return DataStore.createColumnName
  }

  /**
   * 预览autojoin表数据的时候视为预览模式（禁止一些修改操作）
   */
  private get isPreviewMode(): boolean {
    return !!DataStore.autojoinTableName
  }

  /**
   * 是否按住ctrl多选模式：win下按住ctrl键，mac下按住command键
   */
  private isCtrlSelect(event: MouseEvent) {
    if (this.isMac) {
      return event.metaKey
    }
    return event.ctrlKey
  }

  @Watch('tableColumns')
  private onTableColumnsChange(newValue: IColumn[]) {
    /**
     * 利用nextTick避免DataColumn.vue 组件里columnChange和visibleChange的重复接口操作
     * 1、columnChange时，visibleRange为[-1,-1]
     * 2、nextTick里visibleChange触发查询
     */
    this.$nextTick(() => {
      //
      if (newValue.length > 0) {
        console.log('onTableColumnsChange')
        //  remove the formula effect
        DataStore.setShowColumnIndex(false)
        this.initFetchSetting() // 初始化可见区域范围计算

        if (!this.isEditHistory) {
          this.$el.scrollLeft += 1
        }
      }
    })
  }

  public openEditOperator() {
    if (this.isVisitor) {
      this.$message.error('暂无操作权限')
      return
    }
    DataStore.setEditOperatorParam({
      operatorId: this.selectNode.operatorId,
      taskId: this.selectNode.id,
      type: this.selectNode.type,
    })
    DataStore.setEditOperatorNode(this.selectNode)
  }

  @Watch('tableName')
  private onTableChange() {
    DataStore.setColumnFilters([])
    this.clearSelection()
    this.contextmenuVisible = false
    this.visibleRange = [-1, -1] // 把列都设为不可见，避免列信息更新后不必要的queryStat
    this.columnQueryStatCache = {} // 清空缓存
  }

  /**
   * 监听编辑状态变化
   * 分两种情况：
   * 1、对当前处于选中态的历史点编辑按钮（不需要重新获取表、列信息，只需要切换成编辑态）
   * 2、切换到另一个历史记录并编辑（需要重新获取表、列信息，再切换成编辑态）
   * 这里只覆盖第1种情况
   */
  @Watch('isEditHistory')
  private onIsEditHistory(newValue: boolean) {
    if (!this.currentHistory || this.visibleRange[1] < 0) {
      return
    }
    if (newValue) {
      const { data } = this.currentHistory
      const colName =
        data.actionType === StatisticsAction.renameColumn
          ? data.newCol
          : data.col
      // const index = this.tableColumns.findIndex((column: any) => column.name === colName)
      const editColumnIndex = this.getColumnIndex(colName)
      const startIndex = Math.max(
        editColumnIndex - Math.ceil(this.pageSize / 2),
        0
      )
      this.visibleRange = [startIndex, startIndex + this.pageSize]
      this.$el.scrollLeft = this.columnWidth * editColumnIndex

      const target: any = (this.$refs.dataColumn as any).filter(
        (component: any) => component.column.name === colName
      )[0]
      if (target.visible === true) {
        target?.editHistory(this.currentHistory)
      }
    }
  }

  /**
   * 在当前操作历史改变且处于编辑状态下：
   * 1、调整dom的展示，使编辑内容处于可见位置
   * 2、当新旧历史数据只有时间戳不一样时，证明是针对当前active的历史点编辑，手动调用对应列的编辑状态（列状态切换+触发编辑在DataColumn中完成）
   */
  // @Watch('currentHistory')
  // private onCurrentHistoryChange(n:IKeyValueStore, o: IKeyValueStore) {
  //   const newValue = {...n}
  //   const oldValue = {...o}
  //   console.log('onCurrentHistoryChange', newValue)
  //   if (newValue && this.isEditHistory) {
  //     const colName = newValue.data.actionType === StatisticsAction.renameColumn ? newValue.data.newCol : newValue.data.col
  //     const index = this.tableColumns.findIndex((column: any) => column.name === colName)
  //     const target:any = (this.$refs.dataColumn as any)[index]
  //     this.$nextTick(() => {
  //       if (target) {
  //         delete newValue.__stamp
  //         delete oldValue.__stamp
  //         if (isEqual(newValue, oldValue)) {
  //           target.editHistory(newValue)
  //         }
  //       }
  //     })
  //   }
  // }

  @Watch('mergeColumnHotKey')
  private onMergeColumnHotKeyActive(newValue: boolean) {
    // 合并字段快捷键触发
    if (this.selectedColumns.length === 0) {
      return
    }
    if (newValue) {
      const target: any = (this.$refs.dataColumn as any).filter(
        (element: any) => element.column.name === this.selectedColumns[0].name
      )[0]

      target.enableMergeColumn()
    }
  }

  @Watch('createNewColumnFromTable')
  private onCreateNewColumnFromTable(newValue: boolean) {
    //  根据例子创建新列触发
    if (newValue) {
      const target: any = (this.$refs.dataColumn as any).filter(
        (element: any) => element.column.name === this.newColumnName
      )[0]
      target.handleCreateNewColumn()
    }
  }

  private initContextmenu() {
    document.body.append(this.$refs.contextmenuDropdown as Element)
    document.addEventListener('click', this.onDocumentClick)
  }

  /**
   * 初始化分页加载获取数据相关的配置
   */
  initFetchSetting() {
    const { width: containerWidth } = this.$el.getBoundingClientRect()
    const pageSize = Math.ceil(containerWidth / this.columnWidth) + 1
    this.pageSize =
      pageSize > this.tableColumns.length ? this.tableColumns.length : pageSize
    let startIndex = 0
    if (this.isEditHistory && this.currentHistory) {
      const { data } = this.currentHistory
      const colName =
        data.actionType === StatisticsAction.renameColumn
          ? data.newCol
          : data.col
      const editColumnIndex = this.getColumnIndex(colName)
      startIndex = Math.max(editColumnIndex - Math.ceil(this.pageSize / 2), 0)
      this.$el.scrollLeft = this.columnWidth * editColumnIndex
    }
    this.visibleRange = [startIndex, startIndex + this.pageSize]
  }

  private getColumnIndex(columnName: string) {
    if (this.tableColumns.length === 0) {
      return 0
    }
    return this.tableColumns.findIndex((column) => column.name === columnName)
  }

  private containerScroll = debounce(() => this._handleContainerScroll(), 300)

  /**
   * 容器滚动
   */
  private _handleContainerScroll() {
    const container = this.$el
    const { width } = container.getBoundingClientRect()
    const { scrollLeft } = container
    const pageSize = Math.ceil(width / this.columnWidth)
    const leftInvisibleIndex = Math.floor(scrollLeft / this.columnWidth) - 1
    this.visibleRange = [leftInvisibleIndex, leftInvisibleIndex + pageSize]
  }

  beforeDestroy() {
    document.removeEventListener('click', this.onDocumentClick)
  }

  onDocumentClick() {
    // 清空highlight
    // DataStore.setColumnFilters([])
    this.contextmenuVisible = false
  }

  private onDataColumnClick(
    event: MouseEvent,
    column: IColumn,
    index: number,
    formulaFlag?: boolean
  ) {
    DataStore.setShowColumnIndex(false) //  没有及时改变过来
    //  若来自menu formula new column click, formulaFlag 为true ，且设置OnlyShowFormulaCard 为 true
    if (formulaFlag) {
      //  TBD 若该列已经被选中 则return 不再重复点击
      if (
        DataStore.tableSelectColumns.length > 0 &&
        column.name === DataStore.tableSelectColumns[0].name
      ) {
        DataStore.toggleEnableVRPanelRecommend(true)
        DataStore.toggleOnlyShowFormulaCard(true)
        //  handle the bar-click case issue
        DataStore.setVRPanelShow(true)
        DataStore.setTableSelectiontype(SelectionType.columns)
        return
      }
      DataStore.toggleEnableVRPanelRecommend(true)
      DataStore.toggleOnlyShowFormulaCard(true)
    } else {
      DataStore.toggleOnlyShowFormulaCard(false)
    }
    this.clearVisCleanRecommendation() // 清除下方表格的清洗推荐操作
    if (this.isPreviewMode) {
      return
    }
    if (!event.shiftKey) {
      if (this.isCtrlSelect(event)) {
        DataStore.toggleSelectedColumn(column)
      } else if (
        this.selectedColumns.length === 1 &&
        this.selectedColumns[0] === column
      ) {
        DataStore.setSelectedColumns([])
      } else {
        DataStore.setSelectedColumns([column])
      }
      this.lastClickedColumnIndex = index
      this.oldSelectedColumns = this.selectedColumns
    } else {
      const index2 = this.lastClickedColumnIndex ?? 0
      const columns = this.tableColumns.slice(
        Math.min(index, index2),
        Math.max(index, index2) + 1
      )
      DataStore.setSelectedColumns(
        uniq([...this.oldSelectedColumns, ...columns])
      )
    }
    if (this.selectedColumns.length > 0) {
      DataStore.setVRPanelShow(true)
    }
    DataStore.clearTableSelection()
    this.$nextTick(() => {
      if (this.selectedColumns.length > 0) {
        DataStore.setTableSelectiontype(SelectionType.columns)
        DataStore.setTableSelectColumns(this.selectedColumns)
        DataStore.setVrEditTrigger(-1)
      } else {
        DataStore.setTableSelectiontype(SelectionType.none)
      }
    })
  }

  private onBlankClick(event: MouseEvent) {
    // this.clearSelection()
    event.stopPropagation()
  }

  private clearSelection() {
    this.lastClickedColumnIndex = null
    this.oldSelectedColumns = []
    DataStore.clearSelectedColumns()
  }

  private clearVisCleanRecommendation() {
    DataStore.setTableSelectColumns([])
    DataStore.setTableSelectCells([])
    DataStore.setTableSelectionInfo(null)
  }

  /**
   * 触发清洗操作，add/update action
   */
  private async onColumnConfigSuccess(data: any) {
    if (!data || this.isPreviewMode) {
      DataStore.setIsEditHistory(false)
      return
    }
    data = {
      ...data,
      id: this.currentHistory ? this.currentHistory.data.id : '', // 父记录id或者当前编辑的记录id
      table: this.tableName,
    }
    let request = DataStore.addHistory
    if (this.isEditHistory) {
      // 是编辑历史记录的状态
      request = DataStore.updateHistory
      const currentIndex = this.historyList.findIndex(
        (item) => item.data.id === this.currentHistory?.data.id
      )
      data.table = this.historyList[
        currentIndex === 0 ? currentIndex : currentIndex - 1
      ].data.table // 编辑状态下是基于上一条或当前记录的表名来进行筛选
    }
    if (+this.selectNode.type !== 5) {
      // 当前节点不是清洗算子节点，需要新加一个清洗算子节点然后进行筛选
      request = DataStore.addHistory
      await DataStore.selectNodeAddCleanNode()
      const { currentHistory } = await DataStore.getHistoryList()
      data.id = currentHistory.data.id
      data.table = currentHistory.data.table
      // const { output = [] } = newNode.data || {}
      // data.table = output[0] ? output[0].tableName : '' // 表名需要更换成新的表名
    }
    // DataStore.setTableData({
    //   head: [],
    //   data: [] // 清空
    // })
    const { result } = await request({
      data,
    })
    if (+this.selectNode.type === 5) {
      // 当前节点是清洗算子节点，需要先手动刷新节点，避免采样任务刷新状态的滞后性
      DataStore.setLastHistoryCompleteId(result.data.id)
      DataStore.getHistoryList() // 刷新历史记录
    }
    DataStore.setConfirmEditTime(+new Date()) // 更新时间，触发后续节点的更新
    //  DataStore.getHistoryList()
    DataStore.setIsEditHistory(false)
    DataStore.setMergeColumnHotKey(false)
    DataStore.setSelectedColumns([])
    DataStore.setNewColumnOpen(false)

    const status = result.data.status.toLowerCase()
    if (status === 'success') {
      this.$message.success('操作成功')
    } else {
      this.$message.error('操作失败')
    }
  }

  /**
   * 取消清洗面板操作
   */
  private onColumnConfigCancel() {
    DataStore.setIsEditHistory(false)
    DataStore.setMergeColumnHotKey(false)
    DataStore.setSelectedColumns([])
    DataStore.setNewColumnOpen(false)
  }

  /**
   * bar点击后筛选操作
   */
  private onColumnBarFilter(filters: any) {
    if (this.isPreviewMode) {
      return
    }
    if (!isEqual(filters, DataStore.columnFilters)) {
      DataStore.setColumnFilters(filters)
    }
  }

  /**
   * 语义未匹配的bar点击后的操作
   */
  private onOpenVRPanel(parameters: any) {
    DataStore.setOpenVRPanelPara(parameters)
  }

  /**
   * 语义匹配的bar ｜｜ 多个bar 点击后的操作
   */
  private onCloseRecomPart() {
    DataStore.setTableSelectiontype(SelectionType.bars)
  }

  private onContextmenu(event: MouseEvent | null) {
    if (!event) {
      this.contextmenuVisible = false
      return
    }
    this.contextmenuVisible = true
    this.contextmenuStyle = {
      top: event.pageY,
      left: event.pageX,
    }
  }

  /**
   * 右键菜单删除元素
   */
  private onContextmenuDelete() {
    if (this.columnFilters.length === 0) {
      return
    }
    let { columnFilters } = this
    const columnName = columnFilters[0][0].col
    if (columnFilters[0][0].filterType === '=') {
      // 特定值筛选的情况
      columnFilters[0].forEach((item: any) => {
        item.filterType = '<>'
      }) // 换成排除的filterType
    } else if (columnFilters[0][0].filterType === '[a,b)') {
      // 区间情况
      const result: any[] = []
      columnFilters.flat().forEach((item: any) => {
        item.filterType = '![a,b)'
        result.push([item])
      })
      columnFilters = result
    }

    this.onColumnConfigSuccess({
      action: 'FILTER',
      col: columnName,
      filter: columnFilters,
      description: `删除${this.parseRequestDescription()}`,
      actionType: CleanFromVisAction.cleanFromVis,
    })
  }

  /**
   * 右键菜单仅保留元素
   */
  private onContextmenuRetain() {
    if (this.columnFilters.length === 0) {
      return
    }
    this.onColumnConfigSuccess({
      action: 'FILTER',
      col: this.columnFilters[0][0].col,
      filter: this.columnFilters,
      description: `仅保留${this.parseRequestDescription()}`,
      actionType: CleanFromVisAction.cleanFromVis,
    })
  }

  /**
   * 处理操作的description信息，目前只针对右键菜单的 删除/仅保留
   */
  private parseRequestDescription() {
    if (this.columnFilters.length === 0) {
      return ''
    }
    const { columnFilters } = this
    if (['=', '<>'].includes(columnFilters[0][0].filterType)) {
      // 特定值
      return `${columnFilters[0][0].values.length}个值`
    }
    // 范围
    return `${columnFilters[0].length}个范围区间`
  }

  /**
   * 转换语义 (切换接口 addAction)
   * (修改的目标语义 data.toSemantic)  Graph 需要修改
   */
  private async onSemanticChange(data: IChangeSemanticData) {
    this.onColumnConfigSuccess(data) // 走 addAction
  }

  /**
   * 调整 scrollLeft
   */
  public scrollLeft(left = 0) {
    this.$el.scrollLeft = left
  }

  /**
   * 配置面板打开，调整展示的位置（废弃）
   */
  // private onOpenConfigPanel(index: number) {
  //   console.log(index)
  //   const startIndex = index - Math.ceil(this.pageSize / 2)
  //   this.visibleRange = [startIndex, startIndex + this.pageSize]
  //   this.$nextTick(() => {
  //     if (index <= this.visibleRange[0] + 1 || index >= this.visibleRange[1] - 1) {
  //       this.$el.scrollLeft = this.columnWidth * index // 定位到对应的列
  //     }
  //   })
  // }
}
</script>

<style lang="less" scoped>
.columns-container {
  background: #fafafc;
  border: 1px solid #e9e9e9;
  border-bottom-width: 0;
  border-top-width: 0;
  display: flex;
  overflow-x: auto;
  overflow-y: hidden;
  padding: 8px 9px;

  &::after {
    content: '';
    padding-right: 9px;
  }

  &::-webkit-scrollbar {
    height: 6px;
  }

  &::-webkit-scrollbar-thumb {
    background: rgba(144, 147, 153, 0.5);
    border-radius: 6px;
  }

  &::-webkit-scrollbar-track {
    background: transparent;
    border-radius: 5px;
  }

  .empty-info {
    align-items: center;
    display: flex;
    flex: 1;
    justify-content: center;
    text-align: center;
  }

  .edit-opeartor-btn {
    align-items: center;
    background-color: #fff;
    border: 1px solid #5561ff;
    border-radius: 6px;
    color: #5561ff;
    cursor: pointer;
    display: flex;
    font-size: 14px;
    height: 22px;
    justify-content: center;
    line-height: 22px;
    margin: 0 auto;
    padding: 0 5px;
    text-align: center;
    width: 100px;

    span {
      color: #5561ff;
      height: 22px;
    }

    &:hover {
      background-color: #6570ff;
      color: #fff;

      span {
        color: #fff;
      }
    }

    &.disable {
      border-color: #e9e9e9;
      color: #e9e9e9;

      span {
        color: #e9e9e9;
      }

      &:hover {
        background-color: #fff;
        color: #ccc;
      }
    }
  }
}
</style>
<style>
.contextmenu-box {
  position: absolute;
  width: 80px;
}
</style>
